package org.ricks.gen;

import java.net.InetAddress;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 深度优化版雪花算法ID生成器
 * 结构：预留位(1bit) + 时间戳(42bit) + 机器ID(10bit) + 分库分表位(4bit) + 序列号(7bit)
 */
public class EnhancedSnowflake {
    // 基础配置
    private static final long EPOCH = 1672531200000L; // 2023-01-01
    private static final int TIMESTAMP_BITS = 42;
    private static final int WORKER_ID_BITS = 10;
    private static final int SHARD_BITS = 4;
    private static final int SEQUENCE_BITS = 7;

    // 位移计算
    private static final int WORKER_ID_SHIFT = SEQUENCE_BITS + SHARD_BITS;
    private static final int TIMESTAMP_SHIFT = WORKER_ID_SHIFT + WORKER_ID_BITS;
    private static final int SHARD_SHIFT = SEQUENCE_BITS;

    // 最大值计算
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    // 运行时参数
    private final long workerId;
    private long lastTimestamp = -1L;
    private long sequence = 0L;
    private long shardMask = 0L;

    // 缓冲队列
    private LinkedBlockingQueue<Long> idQueue = new LinkedBlockingQueue<>(4096);
    private Thread generatorThread;

    public EnhancedSnowflake() {
        this.workerId = initWorkerId();
        initBufferThread();
    }

    /**
     * 动态获取WorkerID（基于IP末两位）
     */
    private synchronized long initWorkerId() {
        try {
            InetAddress ip = InetAddress.getLocalHost();
            byte[] ipBytes = ip.getAddress();
            return ((ipBytes[ipBytes.length - 2] & 0x03) << 8)
                    | (ipBytes[ipBytes.length - 1] & 0xFF);
        } catch (Exception e) {
            return Thread.currentThread().getId() % MAX_WORKER_ID;
        }
    }

    /**
     * 异步ID生成线程
     */
    private synchronized void initBufferThread() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    if (idQueue.remainingCapacity() > 100) {
                        idQueue.put(nextRawId());
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        generatorThread.setDaemon(true);
        generatorThread.start();
    }

    /**
     * 对外暴露的获取ID方法
     */
    public synchronized long nextId(int shardId) {
        try {
            long baseId = idQueue.take();
            return baseId | ((shardId & 0x0F) << SHARD_SHIFT);
        } catch (InterruptedException e) {
            return nextRawId() | ((shardId & 0x0F) << SHARD_SHIFT);
        }
    }

    /**
     * 核心生成逻辑（带时钟回拨处理）
     */
    private synchronized long nextRawId() {
        long timestamp = timeGen();

        // 时钟回拨处理
        if (timestamp < lastTimestamp) {
            long offset = lastTimestamp - timestamp;
            if (offset <= 5_000) { // 5秒内等待
                try {
                    wait(offset << 1);
                    timestamp = timeGen();
                } catch (InterruptedException e) {
                    throw new RuntimeException("Clock moved backwards");
                }
            } else { // 超过5秒切换备用方案
                return fallbackIdGenerator();
            }
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;
        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
                | (workerId << WORKER_ID_SHIFT)
                | sequence;
    }

    /**
     * 备用ID生成器（基于UUID改造）
     */
    private long fallbackIdGenerator() {
        return Math.abs(UUID.randomUUID().getMostSignificantBits());
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    // 关闭时清理资源
    public void shutdown() {
        if (generatorThread != null) {
            generatorThread.interrupt();
        }
    }
}
